`include  "defines.v"
module wrAXI(
  input clk,
  input rst_n,
  
  input                wr_addr_valid_i,
  input [`PADDR_W-1:0] wr_addr_i,
  input [7:0]          wr_strb_i,
  input [511:0]        wr_data_i,
  output               wr_data_valid_o,

  input                               axi_aw_ready     ,       
  output                              axi_aw_valid     ,   
  output [`AXI_ADDR_WIDTH-1:0]        axi_aw_bits_addr ,   
  output [2:0]                        axi_aw_bits_prot ,   
  output [`AXI_ID_WIDTH-1:0]          axi_aw_bits_id   ,
  output [`AXI_USER_WIDTH-1:0]        axi_aw_bits_user ,     
  output [7:0]                        axi_aw_bits_len  ,      
  output [2:0]                        axi_aw_bits_size ,
  output [1:0]                        axi_aw_bits_burst,
  output                              axi_aw_bits_lock ,   
  output [3:0]                        axi_aw_bits_cache,   
  output [3:0]                        axi_aw_bits_qos  ,   
  
  input                               axi_w_ready      ,  
  output                              axi_w_valid      ,
  output [`AXI_DATA_WIDTH-1:0]        axi_w_bits_data  ,   
  output [`AXI_DATA_WIDTH/8-1:0]      axi_w_bits_strb  ,   
  output                              axi_w_bits_last  ,   
  
  output                              axi_b_ready       ,
  input                               axi_b_valid       ,
  input  [1:0]                        axi_b_bits_resp   ,  
  input  [`AXI_ID_WIDTH-1:0]          axi_b_bits_id     ,
  input  [`AXI_USER_WIDTH-1:0]        axi_b_bits_user    
);

parameter IDLE = 4'b0001,
          AW   = 4'b0010,
          W    = 4'b0100,
          B    = 4'b1000;

reg [3:0] cur_state;
reg [3:0] nxt_state;
always@(posedge clk or negedge rst_n)
  if(~rst_n)
    cur_state <= IDLE;
  else 
    cur_state <= nxt_state;

always@(*)begin
  case(cur_state)
    IDLE:if(wr_addr_valid_i) nxt_state = AW; else nxt_state = IDLE;
    AW  :if(axi_aw_ready && axi_aw_valid) nxt_state = W; else nxt_state=AW;
    W   :if(axi_w_ready  && axi_w_valid && axi_w_bits_last)nxt_state=B;else nxt_state=W;
    B   :if(axi_b_ready  && axi_b_valid) nxt_state = IDLE;else nxt_state=B;
    default:nxt_state=IDLE;
  endcase
end

always@(*)begin
  if(axi_b_ready  && axi_b_valid && (axi_b_bits_resp != 2'b00))begin
    $display("wr recv error resp");
    $finish;
  end
end

reg [3:0]wr_cnt;
always@(posedge clk or negedge rst_n)
  if(~rst_n)
    wr_cnt <= 'd0;
  else if(cur_state == W)begin
    if(axi_w_ready && axi_w_valid)
      wr_cnt <= wr_cnt + 1'b1;
    else 
      wr_cnt <= wr_cnt;
  end else
    wr_cnt <= 'd0;

assign axi_aw_valid      = (cur_state == AW);
assign axi_aw_bits_addr  = {wr_addr_i[31:6] , 6'd0};;
assign axi_aw_bits_prot  = 'd0;
assign axi_aw_bits_id    = 'd1;
assign axi_aw_bits_user  = 'd0;
assign axi_aw_bits_len   = 'd7    ;
assign axi_aw_bits_size  = 3'b011 ;
assign axi_aw_bits_burst = 2'b01  ;
assign axi_aw_bits_lock  =  'd0   ;
assign axi_aw_bits_cache =  'b0010;
assign axi_aw_bits_qos   =  'd0   ;

reg [63:0] wrDataTemp ;
always@(*)begin
  case(wr_cnt)
    'd0:wrDataTemp = wr_data_i[64*1-1:64*0];
    'd1:wrDataTemp = wr_data_i[64*2-1:64*1];
    'd2:wrDataTemp = wr_data_i[64*3-1:64*2];
    'd3:wrDataTemp = wr_data_i[64*4-1:64*3];
    'd4:wrDataTemp = wr_data_i[64*5-1:64*4];
    'd5:wrDataTemp = wr_data_i[64*6-1:64*5];
    'd6:wrDataTemp = wr_data_i[64*7-1:64*6];
    'd7:wrDataTemp = wr_data_i[64*8-1:64*7];
    default: wrDataTemp = 'd0;
  endcase

end
assign axi_w_valid       = (cur_state == W);
assign axi_w_bits_data   = wrDataTemp;
assign axi_w_bits_strb   = 8'hFF;
assign axi_w_bits_last   = (wr_cnt == 'd7);

assign axi_b_ready       = (cur_state == B);
assign wr_data_valid_o   = axi_b_valid && axi_b_ready && (axi_b_bits_resp == 'd0);

endmodule